package com.kingint.sendcarda;

import K720_Package.K720_Serial;

public class SendCard {


    // 静态内部类，用于实现单例模式
    private static class SingletonHolder {
        private static final SendCard INSTANCE = new SendCard();
    }

    // 获取单例实例的方法
    public static SendCard getInstance() {
        return SingletonHolder.INSTANCE;
    }

    // 私有化构造函数，防止外部实例化
    private SendCard() {}




    private K720_Serial k720Serial = null;
    private Byte Mac_Addr = null;
    private boolean check(){
        if (k720Serial == null){
            Result result = openPort();
            if (result.getCode() == 0){
                return false;
            }
            return true;
        }
        return false;
    }


    /**
     * 规范定义
     *
     * load-page 调用【打开串口】
     *
     * 每次回到首页需要执行一次【回收到卡箱】、【命令进卡】
     *
     * --预定吐卡：
     * 1、调用【寻卡】
     * 2、寻卡成功，调用【读取卡号】
     * 3、寻卡失败，调用【检查是否可以发卡】【移动卡片到读卡位】
     * 4、调用【读取卡号】
     * 5、api 记录卡号
     * 6、调用【移动到取卡位】
     *
     * --续住
     * 1、调用【自动进卡】
     * 2、调用【寻卡】
     * 3、寻卡成功、调用【读取卡号】--如果卡号不对或无法获取到房间，调用【移动到取卡位】
     *      * 3.1：在线发卡
     *      * 3.2：发卡成功「预定吐卡」
     * 4、寻卡失败、弹窗提示
     *
     * --退房
     * 1、调用【自动进卡】
     * 2、调用【寻卡】
     * 3、寻卡成功、调用【读取卡号】
     *      * 3.1：接口退卡
     *      * 3.2：判断退卡数量一直
     *      * 3.3：调用【检查是否可以收卡】【回收到卡箱命令】
     * 4、寻卡失败、弹窗提示
     *
     */






    /**
     * 打开串口
     * @return
     */
    public Result openPort(){
        return openPort("/dev/ttyUSB0");
    }
    public Result openPort(String comPort){
        k720Serial = new K720_Serial();  // 实例化串口类
        int result = k720Serial.K720_CommOpen(comPort);  // 打开对应串口
        if (result != 0) {
            return Result.error(-1,"没有找到设备！"+resultByCode(result));
        } else {
            byte i;
            String[] RecordInfo=new String[2];
            int nRet = 0;
            for(i = 0; i < 16; i++){
                nRet = k720Serial.K720_AutoTestMac(i, RecordInfo);
                if(nRet == 0){
                    Mac_Addr = i;
                    return Result.ok(i);
                }
            }
            return Result.error(-1,"打开错误"+resultByCode(nRet));
        }
    }


    /**
     * 首页
     */
    public void indexPage(){
        if (check()){
            return;
        }
        Result result = recycleCard();
        boolean b = cmdInput();
    }


    /**
     * 预定吐卡
     */
    public Result bookingOutCard(){
        Boolean card = findCard();
        if (!card){
            boolean b = checkCardBoxCantOut();
            if (!b){
                return Result.error(-301,"卡箱无卡");
            }
            Boolean b1 = moveCardRead();
            if (!b1){
                return Result.error(-302,"无法出卡");
            }
        }
        //读卡
        return getCardNo();
    }

    private volatile String cardNo = null;

    private Thread workingThread;

    /**
     * 续住/退房进卡返回卡号
     */
    public Result InputCard(){
        if (!autoInput()) {
            return Result.error(-304, "自动进卡失败");
        }

        cardNo = null;

        workingThread = new Thread(() -> {
            try {
                int timeOut = 0;
                boolean found = false;

                while (timeOut < 1200) { // 最多等待 2 分钟 (1200 * 100ms)
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        cardNo = "CANCELLED";
                        return; // 被取消，中断跳出
                    }

                    timeOut++;

                    if (findCard()) {
                        found = true;
                        break;
                    }
                }

                if (!found) {
                    return;
                }

                Result result = getCardNo();
                if (result.getCode() == 0) {
                    cardNo = result.getData().toString();
                    return;
                }

                cardNo = "error";

            } catch (Exception e) {
            }
        });

        workingThread.start();
        return Result.ok();
    }

    /**
     * 中断线程
     */
    public synchronized void cancelInput() {
        if (workingThread != null && workingThread.isAlive()) {
            workingThread.interrupt(); // 打断 sleep
        }
    }

    /**
     * 获取卡号
     * @return
     */
    public Result getCardNoIfReady() {
        if (cardNo != null) {
            if (cardNo.equals("error")){
                moveCardOut();
                return Result.error(-305,"卡号读取失败");
            }
            return Result.ok(cardNo);
        }
        return Result.load();
    }


    /**
     * 回收到卡箱命令
     */
    public Result recycleCard(){
        boolean b = checkCardBoxCantInt();
        if (!b){
            return Result.error(-307,"卡箱已满");
        }
        cancelInput();
        cardNo = null;
        byte[] SendBuf=new byte[3];
        String[] RecordInfo=new String[2];
        SendBuf[0] = 0x44;
        SendBuf[1] = 0x42;
        int result = k720Serial.K720_SendCmd(Mac_Addr, SendBuf, 2, RecordInfo);
        if (result != 0){
            return Result.error(-306,"回收失败");
        } else{
            return Result.ok();
        }

    }







    /**
     * 关闭串口
     * @return
     */
    public Result closePort(){
        if (check()) {
            //没有打开端口
            return Result.error(-2,"没有打开端口");
        }
        int result = k720Serial.K720_CommClose();  // 打开对应串口
        if (result != 0) {
            return Result.error(-1,"关闭串口失败！"+resultByCode(result));
        } else {
            return Result.ok();
        }
    }


    /**
     * 获取设备版本
     * @return
     */
    public Result getDeviceVersion(){
        if (check()) {
            //没有打开端口
            return Result.error(-2,"没有打开端口");
        }
        byte[] _Version=new byte[50];
        String[] RecordInfo=new String[2];
        int result = k720Serial.K720_GetVersion(Mac_Addr, _Version,RecordInfo);
        if (result != 0) {
            return Result.error(-3,"无法获取设备版本，"+resultByCode(result));
        } else {
            return Result.ok(ByteToString(_Version));
        }
    }

    public String ByteToString(byte[] by)
    {
        String str="";
        char ch='\0';
        for(int i=0;by[i]!='\0';i++)
        {
            ch=(char)by[i];
            str+=ch;
        }
        return str;
    }

    /**
     * 读取卡号
     * @return
     */
    public Result getCardNo(){
        if (check()) {
            //没有打开端口
            return Result.error(-2,"没有打开端口");
        }
        String[] RecordInfo=new String[2];
        byte[] CardID=new byte[10];

        int result = k720Serial.K720_S50GetCardID(Mac_Addr, CardID, RecordInfo);;
        if (result != 0) {
            return  Result.error(-303,"获取卡号失败"+resultByCode(result));
        } else {
            String card = Integer.toHexString(CardID[0] & 0xFF).toUpperCase() + Integer.toHexString(CardID[1] & 0xFF).toUpperCase() + Integer.toHexString(CardID[2] & 0xFF).toUpperCase() + Integer.toHexString(CardID[3] & 0xFF).toUpperCase();
            return  Result.ok(card);

        }
    }


    /**
     * 检查设备状态
     * @return
     */
    public Result checkDeviceState(){
        if (check()) {
            //没有打开端口
            return Result.error(-2,"没有打开端口");
        }
        //设备状态
        byte[] deviceState=new byte[10];
        //通道状态
        byte[] transportStatus=new byte[10];
        //卡箱状态
        byte[] cardBoxStatus=new byte[10];
        //回收箱状态
        byte[] retainBoxStatus=new byte[10];
        int result = k720Serial.K720_CheckCardPosition(deviceState, transportStatus, cardBoxStatus,retainBoxStatus);;

        if (result != 0) {
            //没有打开端口
            return Result.error(-1,"查询状态失败"+resultByCode(result));
        }else{
            if (deviceState[0] == 0x31){
                //复位
                reload();
            }

            return Result.ok(new DeviceStateDto().setDeviceState(deviceState[0])
                    .setCardBoxStatus(cardBoxStatus[0])
                    .setRetainBoxStatus(retainBoxStatus[0])
                    .setTransportStatus(transportStatus[0]));

        }

    }

    /**
     * 检查是否可以发卡
     */
    public boolean checkCardBoxCantOut(){
        Result result = checkDeviceState();
        if (result.getCode() != 0){
            return false;
        }
        DeviceStateDto data = (DeviceStateDto)result.getData();
        int cardBoxStatus = data.getCardBoxStatus();

        switch (cardBoxStatus){
            case 0x30:
                //卡箱卡空
                return false;
            case 0x31:
                //卡箱卡少
            case 0x32:
                //卡箱卡足
            case 0x33:
                //卡箱快满
            case 0x34:
                //卡箱满卡
                return true;
            default:
                return false;
        }
    }

    /**
     * 检查是否可以收卡
     */
    public boolean checkCardBoxCantInt(){
        Result result = checkDeviceState();
        if (result.getCode() != 0){
            return false;
        }
        DeviceStateDto data = (DeviceStateDto)result.getData();
        int cardBoxStatus = data.getCardBoxStatus();

        switch (cardBoxStatus){
            case 0x30:
                //卡箱卡空
            case 0x31:
                //卡箱卡少
            case 0x32:
                //卡箱卡足
            case 0x33:
                //卡箱快满
                return  true;
            case 0x34:
                //卡箱满卡
                return false;
            default:
                return false;
        }
    }


    /**
     * 复位
     * @return
     */
    public boolean reload(){
        if (check()) {
            //没有打开端口
            return false;
        }
        byte[] SendBuf=new byte[3];
        String[] RecordInfo=new String[2];
        SendBuf[0] = 0x52;
        SendBuf[1] = 0x53;
        int result = k720Serial.K720_SendCmd(Mac_Addr, SendBuf, 2, RecordInfo);
        if (result == 0){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 自动进卡
     * @return
     */
    public boolean autoInput(){
        if (check()) {
            //没有打开端口
            return false;
        }
        byte[] SendBuf=new byte[3];
        String[] RecordInfo=new String[2];
        SendBuf[0] = 'F';
        SendBuf[1] = 'D';
        SendBuf[2] = '0';

        int result = k720Serial.K720_SendCmd(Mac_Addr, SendBuf, 3, RecordInfo);
        if (result == 0){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 命令进卡
     */
    public boolean cmdInput(){
        if (check()) {
            //没有打开端口
            return false;
        }
        byte[] SendBuf=new byte[3];
        String[] RecordInfo=new String[2];
        SendBuf[0] = 'F';
        SendBuf[1] = 'D';
        SendBuf[2] = '1';

        int result = k720Serial.K720_SendCmd(Mac_Addr, SendBuf, 3, RecordInfo);
        if (result == 0){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 回收到卡箱
     * @return
     */
    public Result recycleToTheCardBox(){
        if (check()) {
            //没有打开端口
            return Result.error(-2,"没有打开端口");
        }
        byte[] SendBuf=new byte[3];
        String[] RecordInfo=new String[2];
        SendBuf[0] = 0x44;
        SendBuf[1] = 0x42;
        int result = k720Serial.K720_SendCmd(Mac_Addr, SendBuf, 2, RecordInfo);
        if (result != 0) {
            return Result.error(-3,"无法回收到卡箱，"+resultByCode(result));
        } else {
            return Result.ok();
        }
    }


    /**
     * 寻卡
     */
    public Boolean findCard(){
        //寻卡
        String[] RecordInfo=new String[2];
        for(int i = 0; i < 3; i++)
        {
            int result = k720Serial.K720_S50DetectCard(Mac_Addr, RecordInfo);
            if(result == 0)
            {
                return true;
            }
        }
        return false;
    }


    /**
     * 移动卡片到读卡位
     */
    public Boolean moveCardRead(){
        String[] RecordInfo=new String[2];
        byte[] SendBuf=new byte[3];
        SendBuf[0] = 0x46;
        SendBuf[1] = 0x43;
        SendBuf[2] = 0x37;
        int result = k720Serial.K720_SendCmd(Mac_Addr, SendBuf, 3, RecordInfo);

        if (result == 0){
            return true;
        }
        return false;
    }

    /**
     * 移动到取卡位
     */
    public Result moveCardOut(){
        String[] RecordInfo=new String[2];
        byte[] SendBuf=new byte[3];
        SendBuf[0] = 0x46;
        SendBuf[1] = 0x43;
        SendBuf[2] = 0x34;
        int result = k720Serial.K720_SendCmd(Mac_Addr, SendBuf, 3, RecordInfo);

        if (result == 0){
            return Result.ok();
        }
        return Result.error(-307,"吐卡失败"+resultByCode(result));
    }


    private String resultByCode(Integer code){
        return K720_Serial.ErrorCode(code, 0);
    }
}
